/* **********************************************************************************
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* This source code is subject to terms and conditions of the Shared Source License
* for DSL Editor PowerToy. A copy of the license can be found in the License.htm file
* at the root of this distribution. If you can not locate the Shared Source License
* for DSL Editor PowerToy, please obtain a copy from: http://www.codeplex.com/dsltreegrideditor/Project/License.aspx.
* By using this source code in any fashion, you are agreeing to be bound by
* the terms of the Shared Source License for DSL Editor PowerToy.
*
* You must not remove this notice, or any other, from this software.
*
* **********************************************************************************/
using System;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Windows.Forms;

using VSTrid = Microsoft.VisualStudio.VirtualTreeGrid;

using DslEditorPowerToy.Controls.VirtualTreeGrid;
using DslEditorPowerToy.Controls.VirtualTreeGrid.Branches;
using DslEditorPowerToy.Controls.VirtualTreeGrid.Validation;

using DslEditorPowerToy.Controls.Editors.Special.DomainModelTreeGrid.Data;

namespace DslEditorPowerToy.Controls.Editors.Special.DomainModelTreeGrid.Branches
{
    /// <summary>
    /// Provides a branch representing the contents of a domain relationship
    /// This branch adds and manages rows for domain classes
    /// </summary>
    internal class DomainRelationshipBranch : DomainElementContainerBranch
    {
        #region Constructors
        public DomainRelationshipBranch(VirtualTreeGridControl treeControl,
            IDomainRelationship branchData, Type branchDataItemType)
            : base(treeControl, branchData, branchDataItemType)
        {
        }
        #endregion

        #region IBranch Members
        /// <summary>
        /// Returns whether to allow expansion of row
        /// </summary>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <returns></returns>
        public override bool IsExpandable(int row, int column)
        {
            DomainElementCollection<IDomainElement> elements = this.GetElementRows();
            if (row >= elements.Count)
                return false;

            IDomainClass domainClass = elements[row] as IDomainClass;
            if ((null != domainClass.ChildRelationships)
                && (domainClass.ChildRelationships.Count > 0))
                return true;
            else
                return false;
        }

        /// <summary>
        /// Locates specified object in branch
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="style"></param>
        /// <param name="locateOptions"></param>
        /// <returns></returns>
        public override VSTrid.LocateObjectData LocateObject(object obj, VSTrid.ObjectStyle style, int locateOptions)
        {
            switch (style)
            {
                case VSTrid.ObjectStyle.TrackingObject:
                    //Since, the items are only accessible in IList by index, we can return by index
                    if (obj is int)
                        return new VSTrid.LocateObjectData((int)obj, 0, (int)VSTrid.TrackingObjectAction.ThisLevel);
                    
                    //Check if of type somewhere under this branch
                    IDomainClass domainClass = null;
                    if (obj is IDomainRelationship)
                        domainClass = ((IDomainRelationship)obj).ParentClass;
                    if (obj is IDomainClass)
                        domainClass = obj as IDomainClass;

                    //Find ancestor relation at this level
                    while (null != domainClass)
                    {
                        //Check if ancestor at this level
                        int index = this.BranchData.ChildClasses.IndexOf(domainClass);
                        if (-1 != index)
                        {
                            //Determine if at this level or a sub level from this level
                            if (obj == domainClass)
                                return new VSTrid.LocateObjectData(index, 0, (int)VSTrid.TrackingObjectAction.ThisLevel);
                            else
                                return new VSTrid.LocateObjectData(index, 0, (int)VSTrid.TrackingObjectAction.NextLevel);
                        }

                        //Move up to grand parent class
                        if (null == domainClass.ParentRelationship)
                            domainClass = null;
                        else
                            domainClass = domainClass.ParentRelationship.ParentClass;
                    }
                    return new VSTrid.LocateObjectData(0, 0, (int)VSTrid.TrackingObjectAction.NotTracked);

                default:
                    break;
            }

            return base.LocateObject(obj, style, locateOptions);
        }
        /// <summary>
        /// Returns the object at specified position and type
        /// </summary>
        /// <param name="row"></param>
        /// <param name="cellColumnIndex"></param>
        /// <param name="style"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public override object GetObject(int row, int column, VSTrid.ObjectStyle style, ref int options)
        {
            switch (style)
            {
                case VSTrid.ObjectStyle.ExpandedBranch:
                    IDomainClass domainClass = GetElementAtRow(row) as IDomainClass;
                    if ((null != domainClass.RelationshipType)
                        && (null != domainClass.ChildRelationships))
                        return new DomainClassBranch(base.TreeControl, domainClass, domainClass.RelationshipType);
                    else
                        return null;

                    case VSTrid.ObjectStyle.TrackingObject:
                    //Only want to track the row (and ignore the column)
                    return GetElementAtRow(row);

                default:
                    return null;
            }
        }

        #endregion

        #region Protected Properties
        protected new IDomainRelationship BranchData
        {
            get
            {
                return base.BranchData as IDomainRelationship;
            }
        }
        #endregion
        
        #region BranchBase Members
        protected override short GetDataItemImageIndex(int row, int column)
        {
            if (0 == column)
                return BranchItemGlyphs.DomainClass;
            else
                return -1;
        }
        #endregion

        #region Protected Methods
        /// <summary>
        /// Returns the row dataItem for this branch
        /// </summary>
        /// <returns></returns>
        protected override DomainElementCollection<IDomainElement> GetElementRows()
        {
            if (null != this.BranchData.ChildClasses)
                return this.BranchData.ChildClasses.ConvertAll();
            else
                return null;
        }
        #endregion
    }
}
